﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Transactions;
using SMA.GENTEv1.Dados;

namespace SMA.GENTEv1
{
    public class FrotaModeloClassificacao
    {
        #region Variaveis Membro
        private int _idFrotaModeloClassificacao;
        private string _descricao;
        private List<CategoriaCNH> _categoriaCNH;
        private GENTEEntities _context;
        private DataTable _gradeClassificacao;
        #endregion

        #region Parametros
        public int IdFrotaModeloClassificacao
        {
            get { return _idFrotaModeloClassificacao; }
            set { _idFrotaModeloClassificacao = value; }
        }

        public string Descricao
        {
            get { return _descricao; }
            set { _descricao = value; }
        }

        public List<CategoriaCNH> CategoriaCNH
        {
            get { return _categoriaCNH; }
            set { _categoriaCNH = value; }
        }
        #endregion

        #region Construtores
        public FrotaModeloClassificacao()
        {
            _context = new GENTEEntities();
        }

        public FrotaModeloClassificacao(int _idfrotamodeloclassificacao, bool _carregaDados)
        {
            _context = new GENTEEntities();
            if (!_carregaDados)
                this._idFrotaModeloClassificacao = _idfrotamodeloclassificacao;
            else
                Carregar(_idfrotamodeloclassificacao);
        }

        public FrotaModeloClassificacao(int _idfrotamodeloclassificacao, bool _carregaDados, bool _carregaCategoriaCNH)
        {
            _context = new GENTEEntities();
            if (!_carregaDados)
                this._idFrotaModeloClassificacao = _idfrotamodeloclassificacao;
            else
                Carregar(_idfrotamodeloclassificacao, _carregaCategoriaCNH);
        }
        #endregion

        #region Métodos Privados
        private static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
        {
            if (null == valueSelector)
            {
                throw new
                    ArgumentNullException("valueSelector");
            }
            if (null == values) { throw new ArgumentNullException("values"); }

            ParameterExpression p = valueSelector.Parameters.Single();
            if (!values.Any())
            {
                return e => false;
            }

            var equals = values.Select(value =>
            (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value,
            typeof(TValue))));
            var body = equals.Aggregate<Expression>((accumulate, equal) =>
            Expression.Or(accumulate, equal));
            return Expression.Lambda<Func<TElement, bool>>(body, p);
        }

        private void Carregar(int _idfrotamodeloclassificacao)
        {
            try
            {
                var consulta = (from classificacao in _context.tab_frota_modelo_classificacao
                                where classificacao.id_frota_modelo_classificacao == _idfrotamodeloclassificacao
                                select classificacao);

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    this._idFrotaModeloClassificacao = list.id_frota_modelo_classificacao;
                    this._descricao = list.descricao;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void Carregar(int _idfrotamodeloclassificacao, bool _carregaCategoriaCNH)
        {
            try
            {
                var consulta = (from classificacao in _context.tab_frota_modelo_classificacao
                                where classificacao.id_frota_modelo_classificacao == _idfrotamodeloclassificacao
                                select classificacao);

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    this._idFrotaModeloClassificacao = list.id_frota_modelo_classificacao;
                    this._descricao = list.descricao;

                    if (_carregaCategoriaCNH)
                    {
                        CategoriaCNH categoria = new CategoriaCNH();
                        this._categoriaCNH = categoria.SelectClassificacaoCNH(list.id_frota_modelo_classificacao);
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void EstruturaExibirGradeClassificacao()
        {
            try
            {
                DataColumn idfrotamodeloclassificacao = new DataColumn();
                idfrotamodeloclassificacao.ColumnName = "IdFrotaModeloClassificacao";
                idfrotamodeloclassificacao.DataType = Type.GetType("System.Int32");
                _gradeClassificacao.Columns.Add(idfrotamodeloclassificacao);

                DataColumn classificacao = new DataColumn();
                classificacao.ColumnName = "Classificacao";
                classificacao.DataType = Type.GetType("System.String");
                classificacao.Caption = "Classificação";
                _gradeClassificacao.Columns.Add(classificacao);

                DataColumn categoriasCNH = new DataColumn();
                categoriasCNH.ColumnName = "CategoriasCNH";
                categoriasCNH.DataType = Type.GetType("System.String");
                categoriasCNH.Caption = "Categorias Habilitação";
                _gradeClassificacao.Columns.Add(categoriasCNH);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private int RetornaIdModeloClassificacao()
        {
            try
            {
                int idclassificacao = 0;

                var consulta = (from classificacao in _context.tab_frota_modelo_classificacao 
                                orderby classificacao.id_frota_modelo_classificacao descending
                                select new
                                {
                                    classificacao.id_frota_modelo_classificacao
                                }).Take(1);

                foreach (var list in consulta.ToList())
                {
                    idclassificacao = list.id_frota_modelo_classificacao;
                }

                return idclassificacao;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void SalvarClassificacaoCategorias()
        {
            for (int i = 0; i < this._categoriaCNH.Count; i++)
            {
                tab_frota_modelo_classificacao_categoria_cnh tabClassificacaoCategoriaCNH = new tab_frota_modelo_classificacao_categoria_cnh();

                tabClassificacaoCategoriaCNH.tab_frota_modelo_classificacaoReference.EntityKey = new EntityKey("GENTEEntities.tab_frota_modelo_classificacao", "id_frota_modelo_classificacao", this._idFrotaModeloClassificacao);
                tabClassificacaoCategoriaCNH.tab_categoria_cnhReference.EntityKey = new EntityKey("GENTEEntities.tab_categoria_cnh", "id_categoria_cnh", this._categoriaCNH[i].IdCategoriaCNH);

                _context.AddTotab_frota_modelo_classificacao_categoria_cnh(tabClassificacaoCategoriaCNH);
                _context.SaveChanges();
            }
        }

        private void ExcluirClassificacaoCategorias()
        {
            var consulta = (from classificacaocategoriaCNH in _context.tab_frota_modelo_classificacao_categoria_cnh
                            where classificacaocategoriaCNH.tab_frota_modelo_classificacao.id_frota_modelo_classificacao == this._idFrotaModeloClassificacao
                            select classificacaocategoriaCNH);

            var listConsulta = consulta.ToList();

            foreach (var list in listConsulta)
            {
                _context.DeleteObject(list);
                _context.SaveChanges();
            }
        }

        private bool VerificaCadastro()
        {
            try
            {
                bool verifica = false;

                if (this._descricao == string.Empty)
                    throw new Exception("É necessário informar a descrição da classificação!");

                if (this._categoriaCNH.Count == 0)
                    throw new Exception("É necessário informar ao menos uma categoria de CNH!");

                if (this._idFrotaModeloClassificacao == 0)
                {
                    var consulta = (from classificacao in _context.tab_frota_modelo_classificacao
                                    where classificacao.descricao == this._descricao
                                    select classificacao);

                    if (consulta.ToList().Count > 0)
                        throw new Exception("Foi encontrado uma classificação com a descrição informada. Operação cancelada!");
                }

                verifica = true;
                return verifica;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

        #region Métodos Públicos

        #region Métodos de Seleção
        public List<FrotaModeloClassificacao> SelectAll()
        {
            try
            {
                List<FrotaModeloClassificacao> listClassificacao = new List<FrotaModeloClassificacao>();

                var consulta = (from classificacao in _context.tab_frota_modelo_classificacao
                                select classificacao);

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    FrotaModeloClassificacao classificacao = new FrotaModeloClassificacao();
                    classificacao.IdFrotaModeloClassificacao = list.id_frota_modelo_classificacao;
                    classificacao.Descricao = list.descricao;

                    listClassificacao.Add(classificacao);
                }

                return listClassificacao;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<FrotaModeloClassificacao> SelectPor(string _descricao)
        {
            try
            {
                List<FrotaModeloClassificacao> listClassificacao = new List<FrotaModeloClassificacao>();

                var consulta = (from classificacao in _context.tab_frota_modelo_classificacao
                                where ((_descricao != "") ? classificacao.descricao.StartsWith(_descricao) : (1 == 1))
                                select classificacao);

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    FrotaModeloClassificacao classificacao = new FrotaModeloClassificacao();
                    classificacao.IdFrotaModeloClassificacao = list.id_frota_modelo_classificacao;
                    classificacao.Descricao = list.descricao;

                    listClassificacao.Add(classificacao);
                }

                return listClassificacao;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<FrotaModeloClassificacao> SelectPor(int[] _idclassificacao)
        {
            try
            {
                List<FrotaModeloClassificacao> listClassificacao = new List<FrotaModeloClassificacao>();

                var consulta = (from classificacao in _context.tab_frota_modelo_classificacao.Where((BuildContainsExpression<tab_frota_modelo_classificacao, int>(item => item.id_frota_modelo_classificacao, _idclassificacao)))
                                select classificacao);

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    FrotaModeloClassificacao classificacao = new FrotaModeloClassificacao();
                    classificacao.IdFrotaModeloClassificacao = list.id_frota_modelo_classificacao;
                    classificacao.Descricao = list.descricao;

                    listClassificacao.Add(classificacao);
                }

                return listClassificacao;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public DataTable SelectClassificacoes(int[] _idclassificacao)
        {
            try
            {
                _gradeClassificacao = new DataTable();

                if (_idclassificacao.Count() == 0)
                    throw new Exception("É necessário selecionar ao menos uma classificação para efetuar a pesquisa!");

                EstruturaExibirGradeClassificacao();

                var consulta = (from classificacao in _context.tab_frota_modelo_classificacao.Where((BuildContainsExpression<tab_frota_modelo_classificacao, int>(item => item.id_frota_modelo_classificacao, _idclassificacao)))
                                select classificacao);

                var listConsulta = consulta.ToList();

                DataRow registro;
                foreach (var list in listConsulta)
                {
                    FrotaModeloClassificacao classificacao = new FrotaModeloClassificacao();
                    classificacao.IdFrotaModeloClassificacao = list.id_frota_modelo_classificacao;
                    classificacao.Descricao = list.descricao;

                    CategoriaCNH categoria = new CategoriaCNH();
                    classificacao.CategoriaCNH = categoria.SelectClassificacaoCNH(list.id_frota_modelo_classificacao);

                    registro = _gradeClassificacao.NewRow();

                    registro["IdFrotaModeloClassificacao"] = classificacao.IdFrotaModeloClassificacao;
                    registro["Classificacao"] = classificacao.Descricao;

                    registro["CategoriasCNH"] = "";
                    if (classificacao.CategoriaCNH.Count > 0)
                    {
                        for (int i = 0; i < classificacao.CategoriaCNH.Count; i++)
                        {
                            registro["CategoriasCNH"] += string.Concat(", ", classificacao.CategoriaCNH[i].Categoria);
                        }
                    }

                    if (registro["CategoriasCNH"].ToString() != string.Empty)
                        registro["CategoriasCNH"] = registro["CategoriasCNH"].ToString().Substring(registro["CategoriasCNH"].ToString().IndexOf(",", 0) + 1).Trim();

                    _gradeClassificacao.Rows.Add(registro);
                }

                return _gradeClassificacao;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        
        #endregion

        #region Métodos de Persistência
        public void Salvar()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                try
                {
                    if (VerificaCadastro())
                    {
                        if (this._idFrotaModeloClassificacao == 0)
                        {
                            tab_frota_modelo_classificacao tabClassificacao = new tab_frota_modelo_classificacao();
                            tabClassificacao.descricao = this._descricao;

                            _context.AddTotab_frota_modelo_classificacao(tabClassificacao);
                            _context.SaveChanges();

                            this._idFrotaModeloClassificacao = RetornaIdModeloClassificacao();

                            SalvarClassificacaoCategorias();
                        }
                        else
                        {
                            tab_frota_modelo_classificacao tabClassificacao = (from classificacao in _context.tab_frota_modelo_classificacao
                                                                               where classificacao.id_frota_modelo_classificacao == this._idFrotaModeloClassificacao
                                                                               select classificacao).First();

                            tabClassificacao.descricao = this._descricao;

                            _context.SaveChanges();

                            ExcluirClassificacaoCategorias();
                            SalvarClassificacaoCategorias();
                        }
                    }

                    scope.Complete();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        public void Excluir()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                try
                {
                    FrotaModelo modelo = new FrotaModelo();
                    int qtdemodelos = 0;

                    qtdemodelos = modelo.SelectQtdeModelos(this._idFrotaModeloClassificacao);

                    if (qtdemodelos > 0)
                        throw new Exception("Esta classificação possui veículo(s) relacionado(s), desta forma, não pode ser efetuado a exclusão. Operação cancelada!");

                    CategoriaCNH categoria = new CategoriaCNH();
                    categoria.ExcluirClassificacao(this._idFrotaModeloClassificacao);

                    var consulta = (from classificacao in _context.tab_frota_modelo_classificacao
                                    where classificacao.id_frota_modelo_classificacao == this._idFrotaModeloClassificacao
                                    select classificacao);

                    var listConsulta = consulta.ToList();

                    foreach (var list in listConsulta)
                    {
                        _context.DeleteObject(list);
                        _context.SaveChanges();
                    }

                    scope.Complete();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }
        #endregion

        #endregion
    }
}
